//
// Created by Symps on 2025/9/14.
//

#ifndef TEST25_6_14_STACK_H
#define TEST25_6_14_STACK_H

#include <iostream>
#include <stdexcept>

using namespace std;

template<typename T>
class Stack {
    friend ostream &operator<<(ostream &out, const Stack<T> &stack) {
        out << "[";
        for (int i = 0; i < stack.size(); i++) {
            out << stack._data[i];
            if (i != stack.size() - 1) {
                out << ", ";
            }
        }
        out << "]";
        return out;
    }

private:
    int _top;
    int _capacity;
    T *_data;
public:
    explicit Stack(int capacity = 10) : _top(-1), _data(new T[capacity]), _capacity(capacity) {}

    Stack(const Stack<T> &stack) {
        _top = stack._top;
        _capacity = stack._capacity;
        _data = new T[stack.size()];
        for (int i = 0; i < stack.size(); i++) {
            _data[i] = stack._data[i];
        }
    }

    ~Stack() {
        delete[] _data;
        _data = nullptr;
        _top = -1;
    }

    [[nodiscard]] int size() const {
        return _top + 1;
    }

    Stack<T> &operator=(const Stack<T> &stack) {
        if (this != &stack) {
            delete[] _data;
            _data = new T[stack.size()];
            for (int i = 0; i < stack.size(); i++) {
                _data[i] = stack._data[i];
            }
        }
        return *this;
    }

    [[nodiscard]] bool empty() const {
        return _top == -1;
    }

    void push(T data) {
        if (size() > _capacity - 1) {
            delete[] _data;
            _data = new T[_capacity * 2];
        } else {
            _data[++_top] = data;
        }
    }

    T& pop() {
        if (size() > 0) {
            return _data[_top--];
        } else {
            throw out_of_range("Stack is empty");
        }
    }

    T& top() const {
        if (size() > 0) {
            return _data[_top];
        } else {
            throw out_of_range("Stack is empty");
        }
    }

    void clear() {
        _top = -1;
    }

};


#endif //TEST25_6_14_STACK_H
